package com.baoyang.service.impl;

import com.baomidou.mybatisplus.core.conditions.interfaces.Func;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baoyang.entity.*;
import com.baoyang.entity.vo.DriverUnloadCountRespVO;
import com.baoyang.entity.vo.InfoRespVO;
import com.baoyang.entity.vo.PcDashboardRespVO;
import com.baoyang.mapper.*;
import com.baoyang.service.BaoyangUserService;
import com.baoyang.tool.utils.JwtUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class BaoyangUserServiceImpl implements BaoyangUserService {
    @Resource
    private BaoyangUserMapper baoyangUserMapper;

    @Resource
    private UserPermissionMapper userPermissionMapper;

    @Resource
    private BaoyangMenuMapper baoyangMenuMapper;

    @Resource
    private BaoyangPermissionMapper baoyangPermissionMapper;

    @Resource
    private ProductNameMapper productNameMapper;

    @Resource
    private PermissionMenuMapper permissionMenuMapper;

    @Resource
    private ContainerMapper containerMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private JwtUtils jwtUtils;

    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    // 包含2025年最新号段（含广电192/移动198等新增号段）
    private static final String PHONE_REGEX =
            "^(13[0-9]|14[014-9]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$";

    public static boolean isValid(String phone) {
        return Pattern.matches(PHONE_REGEX, phone);
    }

    @Override
    public List<BaoyangUser> listAll() {
        return baoyangUserMapper.selectList(null);
    }

    @Override
    public BaoyangUser login(BaoyangUser user) {
        BaoyangUser baoyangUser = baoyangUserMapper
                .selectOne(new QueryWrapper<BaoyangUser>().lambda().eq(BaoyangUser::getUserName, user.getUserName()));
        if (baoyangUser != null && passwordEncoder.matches(user.getPassword(), baoyangUser.getPassword())) {
            if (baoyangUser.getAuditStatus() == 1) {
                throw new RuntimeException("用户未通过审核");
            }
            return baoyangUser;
        }
        return null;
    }

    @Override
    public boolean register(BaoyangUser user) {
        /* 校验手机号 */
        if (StringUtils.hasText(user.getPhone())) {
            if (!isValid(user.getPhone())) {
                throw new RuntimeException("手机号格式错误");
            }
        }
        if (!StringUtils.hasText(user.getUserName())){
            throw new RuntimeException("用户名不能为空");
        }
        if (!StringUtils.hasText(user.getPassword())){
            throw new RuntimeException("密码不能为空");
        }
        if (!StringUtils.hasText(user.getNickName())){
            throw new RuntimeException("昵称不能为空");
        }
        // 检查账号是否已存在
        BaoyangUser baoyangUser = baoyangUserMapper.selectOne(new QueryWrapper<BaoyangUser>().lambda().eq(BaoyangUser::getUserName, user.getUserName()));
        if (Objects.nonNull(baoyangUser)) {
            return false;
        }
        user.setAuditStatus(1);
        // 密码加密
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return baoyangUserMapper.insert(user) > 0;
    }

    @Override
    public BaoyangUser getByUserName(String userName) {
        return baoyangUserMapper
                .selectOne(new QueryWrapper<BaoyangUser>().lambda().eq(BaoyangUser::getUserName, userName));
    }

    @Override
    public IPage<BaoyangUser> pageUserList(Page<BaoyangUser> page, String nickName, Integer auditStatus) {
        QueryWrapper<BaoyangUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.ne("id", 1);
        if (nickName != null && !nickName.trim().isEmpty()) {
            queryWrapper.like("nick_name", nickName);
        }
        if (auditStatus != null) {
            queryWrapper.eq("audit_status", auditStatus);
        }
        queryWrapper.orderByDesc("create_time");
        Page<BaoyangUser> baoyangUserPage = baoyangUserMapper.selectPage(page, queryWrapper);
        List<BaoyangUser> records = baoyangUserPage.getRecords();
        if (CollectionUtils.isNotEmpty(records) && records.stream().filter(a->a.getAuditStatus().equals(2)).count() != 0L) {
            // 所有用户id
            List<Long> userIds = records.stream().map(BaoyangUser::getId).collect(Collectors.toList());
            List<UserPermission> userPermissionList = userPermissionMapper.selectList(new QueryWrapper<UserPermission>().lambda().in(UserPermission::getUserId, userIds));
            // 所有角色id
            List<Long> permissionIds = userPermissionList.stream().map(UserPermission::getPermissionId).distinct().collect(Collectors.toList());
            List<BaoyangPermission> permissionList = baoyangPermissionMapper.selectBatchIds(permissionIds);
            Map<Long, String> permissionNameMap = permissionList.stream().collect(Collectors.toMap(BaoyangPermission::getId, BaoyangPermission::getName));
            Map<Long, UserPermission> userPermissionMap = userPermissionList.stream().collect(Collectors.toMap(UserPermission::getUserId, Function.identity()));
            for (BaoyangUser user : records) {
                if (user.getAuditStatus().equals(2)) {
                    UserPermission userPermission = userPermissionMap.get(user.getId());
                    Long permissionId = userPermission.getPermissionId();
                    user.setPermissionId(permissionId);
                    user.setPermissionName(permissionNameMap.get(permissionId));
                }else{
                    user.setPermissionId(null);
                    user.setPermissionName("");
                }
            }
            baoyangUserPage.setRecords(records);
        }
        return baoyangUserPage;
    }

    @Override
    public boolean audit(BaoyangUser user) {
        BaoyangUser baoyangUser = baoyangUserMapper.selectById(user.getId());
        if (baoyangUser != null) {
            UserPermission userPermission = new UserPermission();
            userPermission.setUserId(user.getId());
            userPermission.setPermissionId(user.getPermissionId());
            userPermissionMapper.insert(userPermission);
            baoyangUser.setAuditStatus(2);
            return baoyangUserMapper.updateById(baoyangUser) > 0;
        }
        return false;
    }

    @Override
    @Transactional
    public boolean update(BaoyangUser user) {
        BaoyangUser updateUser = baoyangUserMapper.selectById(user.getId());
        if (updateUser != null) {
            if (StringUtils.hasText(user.getPhone())) {
                /* 校验手机号 */
                if (!isValid(user.getPhone())) {
                    throw new RuntimeException("手机号格式错误");
                }
                updateUser.setPhone(user.getPhone());
            }
            boolean nickNameFlag = false;
            if (StringUtils.hasText(user.getNickName())) {
                updateUser.setNickName(user.getNickName());
                nickNameFlag = true;
            }
            if (StringUtils.hasText(user.getCarNumber())) updateUser.setCarNumber(user.getCarNumber());
            if (StringUtils.hasText(user.getPassword())) updateUser.setPassword(passwordEncoder.encode(user.getPassword()));
            if (user.getIsDriver() != null) updateUser.setIsDriver(user.getIsDriver());
            /* 修改角色 */
            if (user.getPermissionId() != null) {
                UserPermission userPermission = userPermissionMapper.selectOne(new QueryWrapper<UserPermission>().lambda().eq(UserPermission::getUserId, updateUser.getId()));
                if (userPermission != null) {
                    userPermission.setPermissionId(user.getPermissionId());
                    userPermissionMapper.updateById(userPermission);
                } else {
                    userPermission = new UserPermission();
                    userPermission.setUserId(updateUser.getId());
                    userPermission.setPermissionId(user.getPermissionId());
                    userPermissionMapper.insert(userPermission);
                }
            }
            if (nickNameFlag){
                List<Container> containerList = containerMapper.selectList(new QueryWrapper<Container>().lambda().eq(Container::getDriverId, updateUser.getId()));
                if (!CollectionUtils.isEmpty(containerList)){
                    for (Container container : containerList) {
                        container.setDriverName(user.getNickName());
                        containerMapper.updateById(container);
                    }
                }
            }
            return baoyangUserMapper.updateById(updateUser) > 0;
        }
        return false;
    }

    @Override
    public boolean removeById(String id) {
        return baoyangUserMapper.deleteById(id) > 0;
    }

    @Override
    public InfoRespVO getinfo(String userName) {
        InfoRespVO infoRespVO = new InfoRespVO();
        BaoyangUser user = getByUserName(userName);
        user.setPassword("");
        infoRespVO.setUser(user);
        UserPermission userPermission = userPermissionMapper.selectOne(new QueryWrapper<UserPermission>().lambda().eq(UserPermission::getUserId, user.getId()));
        BaoyangPermission permission = baoyangPermissionMapper.selectById(userPermission.getPermissionId());
        infoRespVO.setPermission(permission);
        List<PermissionMenu> permissionMenuList = permissionMenuMapper.selectList(new QueryWrapper<PermissionMenu>().lambda().eq(PermissionMenu::getPermissionId, permission.getId()));
        List<Long> menuIdList = permissionMenuList.stream().map(PermissionMenu::getMenuId).collect(Collectors.toList());
        List<BaoyangMenu> menuList = baoyangMenuMapper.selectList(new QueryWrapper<BaoyangMenu>().lambda().in(BaoyangMenu::getId, menuIdList));
        infoRespVO.setMenuList(menuList);
        return infoRespVO;
    }

    @Override
    public IPage<DriverUnloadCountRespVO> driverUnloadCount(Integer pageNum, Integer pageSize, String startTime, String endTime, String carNumber, String nickName) {
        Page<DriverUnloadCountRespVO> page = new Page<>(pageNum, pageSize);

        QueryWrapper<BaoyangUser> wrapper = new QueryWrapper<>();
        wrapper.eq("u.is_driver", 2)
                .eq("u.audit_status", 2)
                .eq("u.deleted", 0); // 添加其他条件
        if (StringUtils.hasText(carNumber)) {
            wrapper.like("u.car_number", carNumber);
        }
        if (StringUtils.hasText(nickName)) {
            wrapper.like("u.nick_name", nickName);
        }
        if (StringUtils.hasText(startTime) && StringUtils.hasText(endTime)) {
            wrapper.between("c.unloading_date", startTime, endTime);
        }
        return baoyangUserMapper.selectDriverUnloadStats(page, wrapper);
    }

    @Override
    public PcDashboardRespVO dashboardCount() {
        PcDashboardRespVO pcDashboardRespVO = new PcDashboardRespVO();
        pcDashboardRespVO.setUserCount(
                baoyangUserMapper.selectCount(new QueryWrapper<BaoyangUser>().lambda().ne(BaoyangUser::getId, 1)));
        pcDashboardRespVO
                .setRoleCount(baoyangPermissionMapper.selectCount(new QueryWrapper<BaoyangPermission>().lambda()));
        pcDashboardRespVO.setProductNameCount(productNameMapper.selectCount(new QueryWrapper<ProductName>().lambda()));

        // 获取在线人数统计
        pcDashboardRespVO.setOnlineCount(getOnlineUserCount() - 1);

        return pcDashboardRespVO;
    }

    /**
     * 获取在线用户数量
     * 从Redis中获取所有token，解析用户ID并去重统计
     */
    private Long getOnlineUserCount() {
        try {
            // 获取Redis中所有的token key
            Set<String> tokenKeys = stringRedisTemplate.keys("login:token:*");

            if (tokenKeys == null || tokenKeys.isEmpty()) {
                return 0L;
            }

            // 用于存储去重后的用户ID
            Set<Long> onlineUserIds = tokenKeys.stream()
                    .map(key -> {
                        // 从key中提取token
                        String token = key.replace("login:token:", "");
                        try {
                            // 从token中获取用户ID
                            return jwtUtils.getUserIdFromToken(token);
                        } catch (Exception e) {
                            // 如果token解析失败，返回null
                            return null;
                        }
                    })
                    .filter(Objects::nonNull) // 过滤掉null值
                    .collect(Collectors.toSet()); // 自动去重

            return (long) onlineUserIds.size();
        } catch (Exception e) {
            // 如果出现异常，记录日志并返回0
            System.err.println("获取在线用户数量失败: " + e.getMessage());
            return 0L;
        }
    }

    @Override
    public List<BaoyangUser> driverList() {
        return baoyangUserMapper.selectList(new QueryWrapper<BaoyangUser>().lambda().eq(BaoyangUser::getIsDriver, 2));
    }
}